package com.ruoyi.socket.data;


import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.CoinConstant;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.HttpUtil;
import com.ruoyi.socket.server.WebSocketServer;
import com.ruoyi.trade.domain.TPairs;
import com.ruoyi.trade.mapper.TPairsMapper;
import com.ruoyi.vo.PairsListVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;

@EnableScheduling
@Order(value = 1)
@Component
@Service
@Slf4j
public class DataService implements ApplicationRunner {


	//k线最新数据
	public ConcurrentHashMap<String, Set<String>> map_kline = new ConcurrentHashMap<String, Set<String>>();
	//24小时实时数据
	public ConcurrentHashMap<String, PairsListVo> map_24hour = new ConcurrentHashMap<String, PairsListVo>();


	@Autowired
	private RedisCache redisCache;
	@Resource
	private TPairsMapper pairsMapper;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		(new WebSocketServer()).start(this);
	}

	public Set<String> getKlineByTime(String pairsName, String timeType,String type, Long start, Long end) {
		String redisKey = CacheConstants.KLINE_KEY + type + CacheConstants.SPLIT+ timeType + CacheConstants.SPLIT + pairsName;
		log.info("redisKey="+redisKey);
		log.info("start="+start);
		log.info("end="+end);
		Set<String> set = redisCache.zsetRangByScore(redisKey, start, end);
		return set;
	}




	//获取最新的K线数据
	public Set<String> getInintKline(String pairsName) {
		return map_kline.get(pairsName);
	}

	//获取最新的K线数据放入到map_kline中
	@Scheduled(fixedRate = 10000)
	public void KlineInitLoad() {
		List<TPairs> pairsList = this.getPairsList();
		ThreadPoolExecutor es = new ThreadPoolExecutor(50, 50, 0L, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
			@Override
			public Thread newThread(Runnable r) {
				Thread t = new Thread(r);
				t.setDaemon(true);
				return t;
			}
		});
		for (TPairs pair : pairsList) {
			es.submit(new LoadInitKline(pair.getPairsName(),pair.getType(), redisCache));
		}
		es.shutdown();
	}

	class LoadInitKline implements Runnable{
		private String pairsName;
		private String type;
		private RedisCache redisCache;
		LoadInitKline(String pairsName,String type,RedisCache redisCache){
			this.pairsName=pairsName;
			this.type=type;
			this.redisCache=redisCache;
		}
		@Override
		public void run() {
			String redisKey = CacheConstants.KLINE_KEY + type + CacheConstants.SPLIT+ "timeType" + CacheConstants.SPLIT + pairsName;
			Set<String> set_1m=redisCache.zsetRevRang(redisKey.replace("timeType", "1m"), 0, 0);
			Set<String> set_5m=redisCache.zsetRevRang(redisKey.replace("timeType", "5m"), 0, 0);
			Set<String> set_15m=redisCache.zsetRevRang(redisKey.replace("timeType", "15m"), 0, 0);
			Set<String> set_30m=redisCache.zsetRevRang(redisKey.replace("timeType", "30m"), 0, 0);
			Set<String> set_1h=redisCache.zsetRevRang(redisKey.replace("timeType", "1h"), 0, 0);
			Set<String> set_1d=redisCache.zsetRevRang(redisKey.replace("timeType", "1d"), 0, 0);
			Set<String> set_1w=redisCache.zsetRevRang(redisKey.replace("timeType", "1w"), 0, 0);
			map_kline.put(pairsName+"-1m", set_1m);
			map_kline.put(pairsName+"-5m", set_5m);
			map_kline.put(pairsName+"-15m", set_15m);
			map_kline.put(pairsName+"-30m", set_30m);
			map_kline.put(pairsName+"-1h", set_1h);
			map_kline.put(pairsName+"-1d", set_1d);
			map_kline.put(pairsName+"-1w", set_1w);
		}

	}

	//获取最新24小时数据
	public PairsListVo getInint24Hour(String pairsName) {
		return map_24hour.get("hour-"+pairsName);
	}

	//获取最新24小时数据放到map_24hour中（1秒执行一次）
	@Scheduled(fixedRate = 1000)
	public void hour24InitLoad() {
		List<TPairs> pairsList = this.getPairsList();
		ThreadPoolExecutor es = new ThreadPoolExecutor(50, 150, 0L, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
			@Override
			public Thread newThread(Runnable r) {
				Thread t = new Thread(r);
				t.setDaemon(true);
				return t;
			}
		});
		for (TPairs pair : pairsList) {
			es.submit(new Hour24InitKline(pair.getPairsName(),pair.getType(), redisCache));
		}
		es.shutdown();
	}

	class Hour24InitKline implements Runnable{
		private String pairsName;
		private String type;
		private RedisCache redisCache;
		Hour24InitKline(String pairsName,String type,RedisCache redisCache){
			this.pairsName=pairsName;
			this.type=type;
			this.redisCache=redisCache;
		}
		@Override
		public void run() {
			String contentBn;
			if(type.equals(CoinConstant.Coin_Type.CONTRACT)){//合约
				contentBn =  HttpUtil.doGet("https://api.binance.com/fapi/v1/ticker/24hr?symbol="
						+ pairsName.replace("/", "").toUpperCase());
			}else{
				contentBn =  HttpUtil.doGet("https://api.binance.com/api/v3/ticker/24hr?symbol="
						+ pairsName.replace("/", "").toUpperCase());
			}
			JSONObject jsonObject = JSONObject.parseObject(contentBn);
			String priceChangePercent = jsonObject.get("priceChangePercent").toString();
			String lastPrice = jsonObject.get("lastPrice").toString();
			String highPrice = jsonObject.get("highPrice").toString();
			String lowPrice = jsonObject.get("lowPrice").toString();
			String volume = jsonObject.get("volume").toString();
			String quoteVolume = jsonObject.get("quoteVolume").toString();
			PairsListVo pairsListVo = new PairsListVo();
			pairsListVo.setPairsName(pairsName);
			pairsListVo.setType(type);
			pairsListVo.setPriceChangePercent(priceChangePercent);
			pairsListVo.setLastPrice(lastPrice);
			pairsListVo.setHighPrice(highPrice);
			pairsListVo.setLowPrice(lowPrice);
			pairsListVo.setVolume(volume);
			pairsListVo.setQuoteVolume(quoteVolume);
			map_24hour.put("hour-"+pairsName, pairsListVo);
		}

	}





	public List<TPairs> getPairsList() {
		List<TPairs> cacheList = redisCache.getCacheList("TPairs");
		List<TPairs> pairs;
		if(cacheList !=null && cacheList.size()>0){
			pairs = cacheList;
		}else{
			QueryWrapper<TPairs> wrapper = new QueryWrapper<TPairs>();
			wrapper.eq("state", CoinConstant.Coin_State.NORMAL);
			pairs = pairsMapper.selectList(wrapper);
			redisCache.setCacheList("TPairs", pairs);
			redisCache.expire("TPairs", 5);
		}
		return pairs;
	}

}
